using System;
using System.IO;
using System.Net;
using System.Web;
using System.Xml;
using System.Text;
using System.Threading;
using System.Collections.Generic;
using PickGold.Util;

namespace PickGold.Web
{
	public class CGetFileInfo : CUpDownFile
	{
		protected string _Etag = null;
		protected long _ContentLength = -1;
		protected DateTime _LastModified = DateTime.MinValue;

		public override string Etag
		{
			get
			{
				return this._Etag;
			}
			set
			{
				this._Etag = value;
			}
		}

		public override long ContentLength
		{
			get
			{
				return this._ContentLength;
			}
			set
			{
				this._ContentLength = value;
			}
		}

		public override DateTime LastModified
		{
			get
			{
				return this._LastModified;
			}
			set
			{
				this._LastModified = value;
			}
		}

		public long Write(HttpContext context, string path)
		{
			if (!File.Exists(path))
			{
				context.Response.Clear();
				context.Response.StatusCode = HttpStatus.Value.NOT_FOUND;
				context.Response.StatusDescription = HttpStatus.Message.NOT_FOUND;
				context.Response.End();
				return -1;
			}

			if (this._LastModified == DateTime.MinValue)
				this._LastModified = File.GetLastWriteTime(path);
			return Write(context, new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), path, "application/octet-stream");
		}
		public long Write(HttpContext context, string path, Stream stream)
		{
			return Write(context, stream, path, "application/octet-stream");
		}
		public long Write(HttpContext context, string path, string mime)
		{
			if (!File.Exists(path))
			{
				context.Response.Clear();
				context.Response.StatusCode = HttpStatus.Value.NOT_FOUND;
				context.Response.StatusDescription = HttpStatus.Message.NOT_FOUND;
				context.Response.End();
				return -1;
			}

			if (this._LastModified == DateTime.MinValue)
				this._LastModified = File.GetLastWriteTime(path);
			return Write(context, new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), path, mime);
		}
		public long Write(HttpContext context, Stream stream, string path, string mime)
		{
			if (this._ContentLength <= 0)
				this._ContentLength = stream.Length;
			this.SetRange(context.Request.ServerVariables[HttpHeaderKey.HTTP_RANGE]);
			context.Response.ClearContent();
			if (this._Start <= 0 && this._End >= this._ContentLength - 1)
			{
				context.Response.StatusCode = HttpStatus.Value.OK;
				context.Response.StatusDescription = HttpStatus.Message.OK;
				context.Response.AddHeader(HttpHeaderKey.CONTENT_LENGTH, string.Format("{0}", this._ContentLength));
			}
			else
			{
				context.Response.StatusCode = HttpStatus.Value.PARTIAL_CONTENT;
				context.Response.StatusDescription = HttpStatus.Message.PARTIAL_CONTENT;
				context.Response.AddHeader(HttpHeaderKey.CONTENT_LENGTH, string.Format("{0}", this._End - this._Start + 1));
				context.Response.AddHeader(HttpHeaderKey.CONTENT_RANGE, string.Format("bytes {0}-{1}/{2}", this._Start, this._End, this._ContentLength));
			}
			context.Response.ContentType = mime;
			if (string.IsNullOrEmpty(this._Etag))
				this._Etag = BitConverter.ToString(new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(stream));
			context.Response.AddHeader(HttpHeaderKey.ETAG, this._Etag);
			if (this._LastModified != DateTime.MinValue)
				context.Response.AddHeader(HttpHeaderKey.LAST_MODIFIED, string.Format("{0:R}", this._LastModified));
			else if (File.Exists(path))
				context.Response.AddHeader(HttpHeaderKey.LAST_MODIFIED, string.Format("{0:R}", File.GetLastWriteTime(path)));
			path = path.Replace('\\', '/');
			int i = path.LastIndexOf('/');
			if (i >= 0)
				path = path.Substring(i + 1);
			context.Response.AddHeader(HttpHeaderKey.CONTENT_DISPOSITION, string.Format("attachment; filename={0}", HttpUtility.UrlEncode(path)));
			context.Response.Buffer = false;
			context.Server.ScriptTimeout = int.MaxValue;
			try
			{
				var bs = new byte[BitUtil.K];
				if (stream.Position != this._Start)
					stream.Seek(this._Start, 0);
				this._Current = 0;
				do
				{
					i = stream.Read(bs, 0, BitUtil.K);
					if (i <= 0)
						break;
					if (this._Current + i > this._End - this._Start + 1)
						i = CParser.ConvertTo<int>(this._End - this._Start - this._Current + 1);
					context.Response.OutputStream.Write(bs, 0, i);
					context.Response.OutputStream.Flush();
					this._Current += i;
					this.OnPostBytes(new EventArgs());
				}
				while (context.Response.IsClientConnected);
				context.Response.End();
			}
			catch (Exception x)
			{
				Tracker.WriteError(x);
				this.InnerException = x;
			}
			return this._Current;
		}
		//
	}
}
